package com.mazaiting.instructions.extended;

import com.mazaiting.instructions.base.BytecodeReader;
import com.mazaiting.instructions.base.Index8Instruction;
import com.mazaiting.instructions.base.Instruction;
import com.mazaiting.instructions.base.NoOperandsInstruction;
import com.mazaiting.instructions.loads.*;
import com.mazaiting.instructions.math.IIncInstruction;
import com.mazaiting.instructions.stores.*;
import com.mazaiting.rtda.MtFrame;
import com.mazaiting.util.ByteUtil;

/**
 * wide指令改变其他指令的行为，modifiedInstruction字段存放被改变的指令
 *
 * @author mazaiting
 * @since 2021/8/15
 */
public class WideInstruction {

    public static class Wide extends NoOperandsInstruction {
        /**
         * 字段存放被改变的指令
         */
        private Instruction modifiedInstruction;

        @Override
        public void fetchOperands(BytecodeReader reader) {
            // 先从字节码中读取一字节的操作码，然后创建子指令实例，最后读取子指令的操作数
            short opCode = reader.readU1ToUnsignedByte();
            Index8Instruction instruction;
            switch (opCode) {
                case 0x15: // iload
                    instruction = new ILoadInstruction.ILoad();
                    break;
                case 0x16: // lload
                    instruction = new LLoadInstruction.LLoad();
                    break;
                case 0x17: // fload
                    instruction = new FLoadInstruction.FLoad();
                    break;
                case 0x18: // dload
                    instruction = new DLoadInstruction.DLoad();
                    break;
                case 0x19: // aload
                    instruction = new ALoadInstruction.ALoad();
                    break;
                case 0x36: // istore
                    instruction = new IStoreInstruction.IStore();
                    break;
                case 0x37: // lstore
                    instruction = new LStoreInstruction.LStore();
                    break;
                case 0x38: // fstore
                    instruction = new FStoreInstruction.FStore();
                    break;
                case 0x39: // dstore
                    instruction = new DStoreInstruction.DStore();
                    break;
                case 0x3a: // astore
                    instruction = new AStoreInstruction.AStore();
                    break;
                case 0x84: // iinc
                    instruction = new IIncInstruction.IInc();
                    break;
                case 0xa9: // ret
                    throw new RuntimeException("Unsupported opcode: 0xa9!");
                default:
                    throw new RuntimeException("Unsupported opcode: 0x" + ByteUtil.bytes2HexString(ByteUtil.shortToByte(opCode)));
            }
            instruction.setIndex(reader.readU2ToUnsignedShort());
            // 如果是 iinc
            if (opCode == 0x84) {
                ((IIncInstruction.IInc) instruction).setNum(reader.readU2ToUnsignedShort());
            }
            this.modifiedInstruction = instruction;
        }

        @Override
        public void execute(MtFrame frame) {
            // wide指令只是增加了索引宽度，并不改变子指令操作
            modifiedInstruction.execute(frame);
        }
    }

}
